package com.itstyle.mytest.web;

import com.itstyle.mytest.queue.jvm.MySeckillQueue;
import com.itstyle.mytest.service.IMyTestService;
import com.itstyle.seckill.common.entity.Result;
import com.itstyle.seckill.common.entity.SuccessKilled;
import com.itstyle.seckill.queue.jvm.SeckillQueue;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Api(tags = "我的测试")
@RestController
@RequestMapping("/myTest")
public class MyTestController {
    private final static Logger LOGGER = LoggerFactory.getLogger(MyTestController.class);

    private static int corePoolSize = Runtime.getRuntime().availableProcessors();
    //创建线程池  调整队列数 拒绝服务
    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, corePoolSize + 1, 10l, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000));


    @Autowired
    private IMyTestService testService;

    @ApiOperation(value = "秒杀0 工具测试(仅事务处理 超卖)")
    @PostMapping("/seckill0")
    public Result test0(long seckillId) {

        Random random = new Random();
        long userId = random.nextInt(1000000);
        Result result = testService.startSeckil(seckillId, userId);
        if (result != null) {
            LOGGER.info("用户:{} {}", userId, result.get("msg"));
        } else {
            LOGGER.info("用户:{} {}", userId, "哎呦喂，人也太多了，请稍后！");
        }
        return result;
    }

    @ApiOperation(value = "秒杀零 线程测试(最low实现)(会出现超卖)")
    @PostMapping("/start")
    public Result start(long seckillId) {
        int skillNum = 1000;
        final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
        final long killId = seckillId;

        for (int i = 0; i < skillNum; i++) {
            final long userId = i;
            Runnable task = () -> {
                Result result = testService.startSeckil(killId, userId);
                if (result != null) {
                    LOGGER.info("用户:{}{}", userId, result.get("msg"));
                } else {
                    LOGGER.info("用户:{}{}", userId, "哎呦喂，人也太多了，请稍后！");
                }
                latch.countDown();
            };
            executor.execute(task);
        }
        try {
            latch.await();// 等待所有人任务结束
            LOGGER.info("一共秒杀出{}件商品");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Result.ok();
    }

    @ApiOperation(value = "秒杀一(程序锁)")
    @PostMapping("/startLock")
    public Result startLock(long seckillId) {
        Random random = new Random();
        long userId = random.nextInt(1000000);
        Result result = testService.startSeckilLock(seckillId, userId);
        if (result != null) {
            LOGGER.info("用户:{} {}", userId, result.get("msg"));
        } else {
            LOGGER.info("用户:{} {}", userId, "哎呦喂，人也太多了，请稍后！");
        }
        return result;
    }

    @ApiOperation(value = "秒杀二(AOP程序锁)")
    @PostMapping("/startAopLock")

    public Result startAopLock(long seckillId) {
        Random random = new Random();
        long userId = random.nextInt(1000000);
        Result result = testService.startSeckilAopLock(seckillId, userId);
        if (result != null) {
            LOGGER.info("用户:{} {}", userId, result.get("msg"));
        } else {
            LOGGER.info("用户:{} {}", userId, "哎呦喂，人也太多了，请稍后！");
        }
        return result;
    }

    @ApiOperation(value = "秒杀三（数据库悲观锁）")
    @PostMapping("/startDBPCC_ONE")
    public Result startDBPCC_ONE(long seckillId) {
        Random random = new Random();
        long userId = random.nextInt(1000000);
        Result result = testService.startDBPCC_ONE(seckillId, userId);
        if (result != null) {
            LOGGER.info("用户:{} {}", userId, result.get("msg"));
        } else {
            LOGGER.info("用户:{} {}", userId, "哎呦喂，人也太多了，请稍后！");
        }
        return result;
    }

    @ApiOperation(value = "秒杀四（数据库悲观锁最优实现）")
    @PostMapping("/startDBPCC_TWO")
    public Result startDBPCC_TWO(long seckillId) {
        Random random = new Random();
        long userId = random.nextInt(1000000);
        Result result = testService.startDBPCC_TWO(seckillId, userId);
        if (result != null) {
            LOGGER.info("用户:{} {}", userId, result.get("msg"));
        } else {
            LOGGER.info("用户:{} {}", userId, "哎呦喂，人也太多了，请稍后！");
        }
        return result;
    }

    @ApiOperation(value = "秒杀五（数据库乐观锁）")
    @PostMapping("/startDBOCC")
    public Result startDBOCC(long seckillId) {
        Random random = new Random();
        long userId = random.nextInt(1000000);
        Result result = testService.startDBOCC(seckillId, userId);
        if (result != null) {
            LOGGER.info("用户:{} {}", userId, result.get("msg"));
        } else {
            LOGGER.info("用户:{} {}", userId, "哎呦喂，人也太多了，请稍后！");
        }
        return result;
    }

    @ApiOperation(value="秒杀六(进程内队列)")
    @PostMapping("/startQueue")
    public Result startQueue(long seckillId){
        Random random = new Random();
        long userId = random.nextInt(1000000);
        SuccessKilled kill = new SuccessKilled();
        kill.setSeckillId(seckillId);
        kill.setUserId(userId);
        Boolean flag = null;
        try {
            flag = MySeckillQueue.getMailQueue().produce(kill);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (flag) {
            LOGGER.info("用户:{} {}", userId, "秒杀成功");
        } else {
            LOGGER.info("用户:{} {}", userId, "秒杀失败");
        }
        return Result.ok();
    }

}
